From f93f613aa9873026ccf7b0d625eb86c27b6b42b9 Mon Sep 17 00:00:00 2001
From: Chris Liddell <chris.liddell@artifex.com>
Date: Thu, 1 Oct 2020 15:58:25 +0100
Subject: [PATCH] Searching for a marker in a stream, honor alignment

When searching for markers in a stream buffer, we were "seeking" to the point
in the buffer, and casting to either a byte, ushort or a uint to make the
value comparison. But we cannot do that on SPARC because of the strict
alignment on that hardware.

So, we have to "unpack" the individual bytes from the stream to do the value
comparison.

Note: there are slightly confusing comments in the code that mention being
"on a 16 bit boundary" and "on a 32 bit boundary" - that's referring to the
offset into the buffer, *not* the actual memory address alignment.

Found in testing on Solaris/SPARC
---
 jbig2_mmr.c | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/jbig2_mmr.c b/jbig2_mmr.c
index 578754c..5c39903 100644
--- a/jbig2_mmr.c
+++ b/jbig2_mmr.c
@@ -744,6 +744,16 @@ const mmr_table_node jbig2_mmr_black_decode[] = {
 
 #define getbit(buf, x) ( ( buf[x >> 3] >> ( 7 - (x & 7) ) ) & 1 )
 
+/* On platforms that enforce aligned memory accesses, we can't just
+ * cast the byte * to the type of object we are accessing, we have
+ * unpack the requisite number of bytes, and deal with it that way.
+ * Note that the comments below about being 16/32 bit boundaries
+ * is referring to offsets into the byte stream, *not* memory
+ * addresses.
+ */
+#define getword16(b)  ((uint16_t)(b[0] | (b[1] << 8)))
+#define getword32(b)  ((uint32_t)(getword16(b) | (getword16((b + 2)) << 16)))
+
 static uint32_t
 jbig2_find_changing_element(const byte *line, uint32_t x, uint32_t w)
 {
@@ -817,7 +827,7 @@ jbig2_find_changing_element(const byte *line, uint32_t x, uint32_t w)
         if (w - x < 16) {
             goto check8;
         }
-        if ( ((uint16_t*) line)[ x / 16] != all16) {
+        if ( getword16((line + (x / 8))) != all16) {
             goto check8_no_eof;
         }
         x += 16; /* This will make x a multiple of 32. */
@@ -835,7 +845,7 @@ jbig2_find_changing_element(const byte *line, uint32_t x, uint32_t w)
             look at the next uint16, then uint8, then last 8 bits. */
             goto check16;
         }
-        if (((uint32_t*) line)[x/32] != all32) {
+        if ( getword32((line + (x / 8))) != all32) {
             goto check16_no_eof;
         }
         x += 32;
@@ -849,7 +859,7 @@ jbig2_find_changing_element(const byte *line, uint32_t x, uint32_t w)
     }
 check16_no_eof:
     assert(w - x >= 16);
-    if ( ((uint16_t*) line)[x/16] != all16) {
+    if ( getword16((line + (x / 8))) != all16) {
         goto check8_no_eof;
     }
     x += 16;
@@ -890,6 +900,9 @@ jbig2_find_changing_element(const byte *line, uint32_t x, uint32_t w)
     return x;
 }
 
+#undef getword16
+#undef getword32
+
 static uint32_t
 jbig2_find_changing_element_of_color(const byte *line, uint32_t x, uint32_t w, int color)
 {
